#pragma ident "$Id: IFCBStore.hpp 2897 2011-09-14 20:08:46Z shjzhang $"

/**
 * @file IFCBStore.hpp
 * Store a tabular list of satellite biaes, and compute values at any time
 * from this table. 
 */

//============================================================================
//
//  Shoujian Zhang, Wuhan University, 2012
//
//============================================================================

#include "IFCBStore.hpp"
#include "MiscMath.hpp"

using namespace std;


namespace gpstk
{

   SatIFCB IFCBStore::getValue(const SatID& sat, const CommonTime& time)
      const noexcept(false)
   {
      try {

         bool isExact;
         SatIFCB rec;
         DataTableIterator it1, it2, kt;  

            // Get the data range
         isExact = getTableInterval(sat, time, 1, it1, it2, true );


            // If the time is found in data table, then return directly
         if(isExact) 
         {
            rec = it1->second;
            return rec;
         }

            // Initial time
         CommonTime time0(it1->first);

            // Variables for linear interpolate
         vector<double> times, ifcb;

         kt = it1; 
         while(1) 
         {
               // Inesert time 
            times.push_back( kt->first - time0 );    // sec

            ifcb.push_back( kt->second.ifcb);     


               // End of the data table
            if(kt == it2) break;

               // Increment
            ++kt;
         };

            // interpolate
         double dt(time-time0), slope;

            // linear interpolation
         slope = (ifcb[1]-ifcb[0]) / (times[1]-times[0]);  
         rec.ifcb = ifcb[0] + (dt-times[0])*slope;    // sec/sec

         return rec;
      }
      catch(InvalidRequest& e) { GPSTK_RETHROW(e); }
   }


      // Add a SatIFCB to the store.
   void IFCBStore::addSatIFCB(const SatID& sat, 
                              const CommonTime& time,
                              const SatIFCB& rec)
      noexcept(false)
   {
      try 
      {

         if( tables.find(sat) != tables.end() ) 
         {
            if( tables[sat].find(time) != tables[sat].end() )
            {
                  // Update the old data record
               SatIFCB& oldrec(tables[sat][time]);
               oldrec.ifcb = rec.ifcb;

            }
            else
            {
               tables[sat][time] = rec;
            }

         }
         else  // Add directly
         {
            tables[sat][time] = rec;
         }
      }
      catch(InvalidRequest& ir) 
      { 
         GPSTK_RETHROW(ir); 
      }
   }


      /// Load a satellite upd file 
   void IFCBStore::loadFile(const std::string& filename) 
       noexcept(false)
   {
      try 
      {

            // open the input stream
         IFCBStream strm(filename.c_str());

         if(!strm.is_open()) 
         {
            Exception e("File " + filename + " could not be opened");
            GPSTK_THROW(e);
         }
         strm.exceptions(std::ios::failbit);
      // cout << "Opened file " << filename << endl;

            // declare header and data
         IFCBData data;

            // read data
         try
         {
            while(strm >> data) 
            {
               SatIFCB rec;
               rec.ifcb = data.ifcb; 
               addSatIFCB(data.sat, data.time, rec);
            }
         }
         catch(Exception& e) 
         {
            e.addText("Error reading data of file " + filename);
            GPSTK_RETHROW(e);
         }

            // close
         strm.close();

      }
      catch(Exception& e) 
      { 
          GPSTK_RETHROW(e); 
      }

   }  // end IFCBStore::loadFile()


}  // End of namespace gpstk
